﻿using System;
using System.Collections.Generic;
using MentalAlchemy.Atomics;

namespace MentalAlchemy.Molecules
{
	/// <summary>
	/// Class to represent BNF expressions and utility methods.
	/// </summary>
	[Serializable]
	public class BNFExpression
	{
		#region - Const strings. -
		public const string DEFAULT_ARITHMOP_BNF_NAME = "ArithmeticOp";
		public const string DEFAULT_ASSIGN_BNF_NAME = "Assignment";
		public const string DEFAULT_BODY_BNF_NAME = "Body";
		public const string DEFAULT_CONDITION_BNF_NAME = "Condition";
		public const string DEFAULT_CONDITION_EXPR_BNF_NAME = "CondExpr";
		public const string DEFAULT_EXIT_BNF_NAME = "Exit";
		public const string DEFAULT_EXPRESSION_BNF_NAME = "Expression";
		public const string DEFAULT_EXPRESSION_TERM_BNF_NAME = "ExpTerm";
		public const string DEFAULT_FUNCCALL_BNF_NAME = "FuncCall";
		public const string DEFAULT_HEADER_BNF_NAME = "Header";
		public const string DEFAULT_LIST_BNF_NAME = "List";
		public const string DEFAULT_LISTITEM_BNF_NAME = "ListItem";
		public const string DEFAULT_LOGICOP_BNF_NAME = "LogicOp";
		public const string DEFAULT_LOOP_BNF_NAME = "Loop";
		public const string DEFAULT_OPERATION_BNF_NAME = "Operation";
		public const string DEFAULT_SEQUENCE_BNF_NAME = "Sequence";
		public const string DEFAULT_SEQUENCE_ITEM_BNF_NAME = "SeqItem";
		public const string DEFAULT_TREE_BNF_NAME = "Tree";

		public const string DEFAULT_CONDITION_KEYWORD = "if";
		public const string DEFAULT_ELSE_KEYWORD = "else";
		public const string DEFAULT_EXIT_KEYWORD = "exit";
		public const string DEFAULT_EXPRESSION_END_SYMBOL = ";";
		public const string DEFAULT_FALSE_KEYWORD = "false";
		public const string DEFAULT_HEADER_KEYWORD = "script";
		public const string DEFAULT_LOOP_KEYWORD = "while";
		public const string DEFAULT_TRUE_KEYWORD = "true";
		public const string DEFAULT_AND_KEYWORD = "and";
		public const string DEFAULT_OR_KEYWORD = "or";

		public const string DEFAULT_LESS_OPERATOR = "<";
		public const string DEFAULT_LESS_EQUAL_OPERATOR = "<=";
		public const string DEFAULT_MORE_OPERATOR = ">";
		public const string DEFAULT_MORE_EQUAL_OPERATOR = ">=";
		public const string DEFAULT_EQUAL_OPERATOR = "==";
		public const string DEFAULT_UNEQUAL_OPERATOR = "!=";
		public const string DEFAULT_PLUS_OPERATOR = "+";
		public const string DEFAULT_MINUS_OPERATOR = "-";
		public const string DEFAULT_MULT_OPERATOR = "*";
		public const string DEFAULT_DIVIDE_OPERATOR = "/"; 
		#endregion

		public string Name;
		public string Alias = "";
		public List<Token[]> Syntaxis;
		public bool IsRecursive;

		#region - Public methods. -
		/// <summary>
		/// [molecule]
		/// 
		/// Checks whether given set of tokens satisfy syntaxis rules for the BNF expression.
		/// </summary>
		/// <param name="tokens">List of tokens.</param>
		/// <param name="synt">Script syntaxis.</param>
		/// <returns>True if validation passes and False otherwise.</returns>
		public bool Validate(List<Token> tokens, ScriptSyntaxis synt)
		{
			foreach (var scase in Syntaxis)
			{	// check each syntaxical variant.
				bool passed = true;
				for (int i = 0, count = 0; i < scase.Length; i++, count++)
				{
					if (scase[i].TokenType == TokenType.BNFConstruct && tokens[count].TokenType != TokenType.BNFConstruct)
					{
						// perform partial validation for [tokens].
						var sub = tokens.GetRange(i, tokens.Count - i);
						var bnf = synt.GetBNFByName(scase[i].Text);
						bnf.ValidatePartial(sub, synt, out count);
						count--;	// in order not to jump over a token.
					}
					else if (scase[i].TokenType != TokenType.BNFConstruct && tokens[count].TokenType == TokenType.BNFConstruct)
					{
						// perform partial validation for [scase].
						var sub = VectorMath.Subvector(scase, i, scase.Length - 1);
						var bnf = synt.GetBNFByName(tokens[count].Text);
						bnf.ValidatePartial(new List<Token>(sub), synt, out i);
						i--;
					}
					else
					{	// perform usual comparison of tokens.
						var compres = scase[i].Equals(tokens[count]);
						if (!compres)
						{
							passed = false;
							break;
						}
					}
				}

				if (passed)
				{	// if validation was succesful for [scase].
					// substitute first [scase.Length] tokens by the current BNF construct.
					// and call this function recursively.
					var token = new Token();
					token.TokenType = TokenType.BNFConstruct;
					token.Text = Name;
					var res = new List<Token>();
					res.Add(token);
					res.AddRange(tokens.GetRange(scase.Length, tokens.Count - scase.Length));
					return Validate(res, synt);
				}
			}

			return false;
		}

		/// <summary>
		/// [molecule]
		/// 
		/// Tries to perform validation of the input list of tokens from the specified position
		/// until validation is succesful and returns index of the first token which breaks the validation.
		/// </summary>
		/// <param name="tokens">List of tokens to validate.</param>
		/// <param name="synt">Script syntaxis.</param>
		/// <param name="stopIdx"></param>
		/// <returns></returns>
		public bool ValidatePartial(List<Token> tokens, ScriptSyntaxis synt, out int stopIdx)
		{
			foreach (var scase in Syntaxis)
			{	// check each syntaxical variant.
				bool passed = true;
				for (int i = 0, count = 0; i < scase.Length; i++, count++)
				{
					if (scase[i].TokenType == TokenType.BNFConstruct && tokens[count].TokenType != TokenType.BNFConstruct)
					{
						// perform partial validation for [tokens].
						var sub = tokens.GetRange(count, tokens.Count - count);
						var bnf = synt.GetBNFByName(scase[i].Text);
						bnf.ValidatePartial(sub, synt, out stopIdx);
						stopIdx += tokens.Count - count - 1;
						count = stopIdx - 1;	// in order not to jump over a token.
					}
					else
					{	// perform usual comparison of tokens.
						var compres = scase[i].Equals(tokens[count]);
						if (!compres)
						{
							passed = false;
							break;
						}
					}
				}

				if (passed)
				{	// if validation was succesful for [scase].
					// substitute first [scase.Length] tokens by the current BNF construct.
					// and call this function recursively.
					var token = new Token();
					token.TokenType = TokenType.BNFConstruct;
					token.Text = Name;
					var res = new List<Token>();
					res.Add(token);
					res.AddRange(tokens.GetRange(scase.Length, tokens.Count - scase.Length));

					var validationRes = ValidatePartial(res, synt, out stopIdx);
					stopIdx += scase.Length - 1;	// increase by the number of removed tokens.
					return validationRes;
				}
			}

			stopIdx = 0;
			return false;
		}

		/// <summary>
		/// [molecule]
		/// 
		/// Tries to perform validation of the input list of tokens from the specified position
		/// until validation is succesful and returns index of the first token which breaks the validation.
		/// </summary>
		/// <param name="tokens">List of tokens to validate.</param>
		/// <param name="synt">Script syntaxis.</param>
		/// <param name="stopIdx">Index of token at which BNF expression was stopped.</param>
		/// <returns>Created parse tree node or null.</returns>
		public ParseTreeNode CreateParseTreeNode(List<Token> tokens, ScriptSyntaxis synt, out int stopIdx)
		{
			var resNodes = new ParseTreeNode[Syntaxis.Count];
			var resStopIdx = new int[Syntaxis.Count];
			for (int i1 = 0; i1 < Syntaxis.Count; i1++)
			{
				var scase = Syntaxis[i1];

				//var subNodes = new List<ParseTreeNode>();
				var node = new ParseTreeNode();
				node.Contents = Name;
				//var parentNode = node;

				// check each syntaxical variant.
				var passed = true;
				var count = 0;
				if (scase.Length <= tokens.Count)
				{
					var subNodes = new List<ParseTreeNode>();
					var tempCount = 0;
					passed = TryParse(i1, tokens, count, synt, out subNodes, out tempCount);

					if (passed)
					{
						//tokens[count].BnfLen = tempCount + 1;
						//tokens[count].BnfName = Name;
						node.ChildNodes.AddRange(subNodes);
						count = tempCount;
					}
				}
				else
				{
					passed = false;
				}

				if (passed)
				{
					#region - Try recursion. -
					if (IsRecursive)
					{
						// enable recursion only if it makes sense, because not all BNF constructs are recursive.
						// if validation was succesful for [scase].
						// substitute first [scase.Length] tokens by the current BNF construct.
						// and call this function recursively.
						var token = new Token { TokenType = TokenType.BNFConstruct, Text = Name };
						var res = new List<Token>();
						res.Add(token);
						res.AddRange(tokens.GetRange(count + 1, tokens.Count - count - 1));

						// substitute current node by 'higher level' node.
						var tempCount = 0;
						var tempNode = CreateParseTreeNode(res, synt, out tempCount);

						// assign sub-nodes (side-nodes?).
						if (tempNode != null)
						{
							node.ChildNodes.AddRange(tempNode.ChildNodes);
							count += tempCount;	// -1 because [res] has extra token at the beginning.
						}
					}
					//else
					//{
					//    count--;	// in order not to jump over some token.
					//}
					#endregion

					resNodes[i1] = node;
					resStopIdx[i1] = count;
				}
				else
				{	// passed == false.
					resNodes[i1] = null;
					resStopIdx[i1] = -1;
				}
			}

			// select element of [resNodes] with the largest stopIdx.
			var max = VectorMath.IndexOfMax(resStopIdx);
			stopIdx = resStopIdx[max];
			var resNode = resNodes[max];
			if (resNode != null)
			{
				resNode.Bnf = this;
				resNode.Token = tokens[0];
				tokens[0].BnfLen = stopIdx + 1;
				tokens[0].BnfName = Name;

				// assign [Parent] property for child nodes.
				foreach (var child in resNode.ChildNodes)
				{
					child.Parent = resNode;
				}
			}

			return resNode;
		}

		/// <summary>
		///  
		/// Tries to parse given list of tokens starting from the prescribed position.
		/// If successful returns [True] and sets output arguments [subNodes] and [stopIdx]
		/// </summary>
		/// <param name="scaseIdx"></param>
		/// <param name="tokens"></param>
		/// <param name="pos"></param>
		/// <param name="synt"></param>
		/// <param name="subNodes"></param>
		/// <param name="stopIdx"></param>
		/// <returns></returns>
		public bool TryParse(int scaseIdx, List<Token> tokens, int pos, ScriptSyntaxis synt, out List<ParseTreeNode> subNodes, out int stopIdx)
		{
			var scase = Syntaxis[scaseIdx];
			var count = pos;

			subNodes = new List<ParseTreeNode>();
			for (int i = 0; i < scase.Length && count < tokens.Count; i++, count++)
			{
				if (tokens[count].BnfLen > 0
					&& scase[i].TokenType == TokenType.BNFConstruct
					&& string.Compare(scase[i].Text, tokens[count].BnfName, true) == 0)
				{	// this token has already been parsed.
					// create a subnode.
					var subNode = new ParseTreeNode();
					subNode.Contents = tokens[count].BnfName;
					var length = tokens[count].BnfLen;
					for (int j = 0; j < length; j++)
					{
						var tempSubNode = new ParseTreeNode(tokens[count + j]);
						subNode.ChildNodes.Add(tempSubNode);
					}
					subNodes.Add(subNode);
					count += tokens[count].BnfLen - 1;
					continue;
				}
				if (scase[i].TokenType == TokenType.BNFConstruct
					&& tokens[count].TokenType != TokenType.BNFConstruct
					//&& scase[i].Text != Name)	// the last condition is required to avoid infinite recursion.
					&& (scase[i].Text != Name || count > 0))	// the last condition is required to avoid infinite recursion.
				{
					// perform partial validation for [tokens].
					var sub = tokens.GetRange(count, tokens.Count - count);
					var bnf = synt.GetBNFByName(scase[i].Text);
					var tempCount = 0;
					var subNode = bnf.CreateParseTreeNode(sub, synt, out tempCount);
					if (subNode != null)
					{
						subNode.Token = tokens[count];
						subNode.Bnf = bnf;
						subNode.Contents = scase[i].Text;
						subNodes.Add(subNode);
						count += tempCount; // in order not to jump over a token.
					}
					else
					{
						subNodes = null;
						stopIdx = -1;
						return false;
					}
				}
				else
				{
					//
					// perform usual comparison of tokens.
					var compres = scase[i].Equals(tokens[count]);
					if (!compres)
					{
						subNodes = null;
						stopIdx = -1;
						return false;
					}

					//
					// omit some token types.
					if (tokens[count].TokenType == TokenType.OpeningBracket
						|| tokens[count].TokenType == TokenType.ClosingBracket
						|| tokens[count].TokenType == TokenType.Punctuation
						|| tokens[count].TokenType == TokenType.ExpressionEnd)
					{
						continue;
					}

					//
					// to avoid tautology.
					if ((tokens[count].TokenType == TokenType.Keyword)
						&& (string.Compare(tokens[count].Text, Name, true) == 0
							|| string.Compare(tokens[count].Text, Alias, true) == 0))
					{
						continue;
					}

					//
					// to avoid tautology.
					if ((tokens[count].TokenType == TokenType.BNFConstruct)
						&& (string.Compare(tokens[count].Text, Name, true) == 0
							|| string.Compare(tokens[count].Text, Alias, true) == 0))
					{
						continue;
					}

					// create sub-node.
					var subNode = new ParseTreeNode();
					subNode.Token = tokens[count];
					subNode.Contents = tokens[count].Text;
					subNodes.Add(subNode);
				}
			}

			stopIdx = count - 1;	// -1 because [count] is larger then the last index by 1 (due to increment at the iteration end).
			return true;
		}
		#endregion

		#region - Default BNF constructs. -
		/// <summary>
		/// Returns BNF construct for arithmetic operations:
		///		<List> ::= > | < | >= | <= | == | != | !
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ArithmeticOperation()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_ARITHMOP_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "+") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "-") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "*") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "/") });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for assignment operation:
		///		<Assign> ::= <id> = <Expression> | <id> = <FuncCall>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Assign()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_ASSIGN_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.Operator, "="), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			//res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.Operator, "="), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.Operator, "="), new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME) });
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for condition:
		///		<Condition> ::= if (<ConditionalExpression>) {<Body>}
		/// todo: add [else] branch.
		/// todo: add [if else] branch.
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Condition()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_CONDITION_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_CONDITION_KEYWORD), new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME), new Token(TokenType.ClosingBracket, ")"),
									 new Token(TokenType.OpeningBracket, "{"), new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_BNF_NAME), new Token(TokenType.ClosingBracket, "}")});
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_BNF_NAME), new Token(TokenType.Keyword, DEFAULT_ELSE_KEYWORD),
									 new Token(TokenType.OpeningBracket, "{"), new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_BNF_NAME), new Token(TokenType.ClosingBracket, "}")});
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_BNF_NAME), new Token(TokenType.Keyword, DEFAULT_ELSE_KEYWORD), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_BNF_NAME) });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for conditional expression:
		///		<CondExpr> ::= true | false | <id> | (<ExpTerm>) | <ExpTerm> > <ExpTerm> | <ExpTerm> < <ExpTerm> | <ExpTerm> == <ExpTerm> | <ExpTerm> != <ExpTerm>
		///					 | <CondExpr> and <CondExpr> | <CondExpr> or <CondExpr> | !<CondExpr>
		/// todo: add [else] branch.
		/// todo: add [if else] branch.
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ConditionalExpression()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_CONDITION_EXPR_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_TRUE_KEYWORD) });
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_FALSE_KEYWORD) });
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, "") });
			res.Syntaxis.Add(new[] { new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME), new Token(TokenType.ClosingBracket, ")") });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_LOGICOP_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME) });
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_LOGICOP_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME), new Token(TokenType.Operator, "and"), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME), new Token(TokenType.Operator, "or"), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "!"), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME) });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for exit command
		///		<Exit> ::= exit
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Exit()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_EXIT_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_EXIT_KEYWORD), new Token(TokenType.ExpressionEnd, DEFAULT_EXPRESSION_END_SYMBOL), });
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for mathematical expression:
		///		<Expression> ::= <ExpTerm> | <ExpTerm> <MathOp> <ExpTerm>
		///						| <ExpTerm> <LogicOp> <ExpTerm>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Expression()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_EXPRESSION_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			// id.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, "") });
			// func. call.
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME) });
			// sign change.
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "+"), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			// sign change.
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "-"), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			// object function call.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.Operator, "."), new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME) });
			// arithmetic operation.
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_ARITHMOP_BNF_NAME), new Token(TokenType.Identifier, "") });
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_LOGICOP_BNF_NAME), new Token(TokenType.Identifier, "") });
			// arithmetic operation.
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_ARITHMOP_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_LOGICOP_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });
			// brackets.
			res.Syntaxis.Add(new[] { new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.ClosingBracket, ")") });
			// indexing.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.OpeningBracket, "["), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME), new Token(TokenType.ClosingBracket, "]") });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for mathematical expression term:
		///		<ExpTerm> ::= <id> | <FuncCall> | <id>.<FuncCall>
		///                 | -<ExpTerm> | +<ExpTerm> | | (<ExpTerm>) <id>[<ExpTerm>]
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ExpressionTerm()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_EXPRESSION_TERM_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			// id.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, "") });
			// func. call.
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME) });
			// sign change.
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "+"), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME) });
			// sign change.
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "-"), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME) });
			// brackets.
			res.Syntaxis.Add(new[] { new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME), new Token(TokenType.ClosingBracket, ")") });
			// indexing.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.OpeningBracket, "["), new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_TERM_BNF_NAME), new Token(TokenType.ClosingBracket, "]") });
			// object function call.
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.Operator, "."), new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME) });
			res.IsRecursive = true;
			return res;
		}

		// todo: take into consideration bracket constructions for expressions.
		// todo: take into consideration sign change for expressions.

		/// <summary>
		/// Returns BNF construct for function calls:
		///		<FuncCall> ::= <id> (<List>)
		/// </summary>
		/// <returns></returns>
		public static BNFExpression FunctionCall()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_FUNCCALL_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.OpeningBracket, "("),
									new Token(TokenType.BNFConstruct, DEFAULT_LIST_BNF_NAME), new Token(TokenType.ClosingBracket, ")") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, ""), new Token(TokenType.OpeningBracket, "("), new Token(TokenType.ClosingBracket, ")") });
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for header:
		///		<Header> ::= Script <id> | <Header> (<List>)
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Header()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_HEADER_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_HEADER_KEYWORD), new Token(TokenType.Identifier, "") });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_HEADER_BNF_NAME), new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_LIST_BNF_NAME), new Token(TokenType.ClosingBracket, ")") });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for lists:
		///		<List> ::= <ListItem> | <List>, <ListItem>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ListExpression()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_LIST_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_LISTITEM_BNF_NAME) });	// single list item
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_LIST_BNF_NAME), new Token(TokenType.Punctuation, ","), new Token(TokenType.BNFConstruct, DEFAULT_LISTITEM_BNF_NAME) });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for list items:
		///		<ListItem> ::= <id>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ListItemExpression()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_LISTITEM_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Identifier, "") });	// simple id
			//res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME) });	// any expression.
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for logical operations:
		///		<List> ::= > | < | >= | <= | == | != | !
		/// </summary>
		/// <returns></returns>
		public static BNFExpression LogicalOperation()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_LOGICOP_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, ">") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "<") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, ">=") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "<=") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "==") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "!=") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "!") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "and") });
			res.Syntaxis.Add(new[] { new Token(TokenType.Operator, "or") });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for loops:
		///		<Loop> ::= while (<CondExpr>) {<Sequence>}
		/// </summary>
		/// <returns></returns>
		public static BNFExpression LoopExpression()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_LOOP_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.Keyword, DEFAULT_LOOP_KEYWORD), new Token(TokenType.OpeningBracket, "("), new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_EXPR_BNF_NAME), new Token(TokenType.ClosingBracket, ")"),
									 new Token(TokenType.OpeningBracket, "{"), new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_BNF_NAME), new Token(TokenType.ClosingBracket, "}")});
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for operations:
		///		<Operation> ::= <FuncCall>; | <Expression>; | <Assignment>;
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Operation()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_OPERATION_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME), new Token(TokenType.ExpressionEnd, ";") });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_EXPRESSION_BNF_NAME), new Token(TokenType.ExpressionEnd, ";") });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_ASSIGN_BNF_NAME), new Token(TokenType.ExpressionEnd, ";") });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_ITEM_BNF_NAME), new Token(TokenType.ExpressionEnd, ";") });
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for sequence:
		///		<Sequence> ::= <SeqItem> | <Sequence> <SeqItem>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression Sequence()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_SEQUENCE_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_ITEM_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_ITEM_BNF_NAME) });
			res.IsRecursive = true;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for sequence item:
		///		<SeqItem> ::= <Assign>; | <FuncCall>; | <Condition> | ;
		/// </summary>
		/// <returns></returns>
		public static BNFExpression SequenceItem()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_SEQUENCE_ITEM_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_ASSIGN_BNF_NAME), new Token(TokenType.ExpressionEnd, DEFAULT_EXPRESSION_END_SYMBOL) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_FUNCCALL_BNF_NAME), new Token(TokenType.ExpressionEnd, DEFAULT_EXPRESSION_END_SYMBOL) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_CONDITION_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_LOOP_BNF_NAME) });
			res.Syntaxis.Add(new[] { new Token(TokenType.ExpressionEnd, DEFAULT_EXPRESSION_END_SYMBOL) });
			res.IsRecursive = false;
			return res;
		}

		/// <summary>
		/// Returns BNF construct for a script tree:
		///		<Tree> ::= <Header> <Sequence>
		/// </summary>
		/// <returns></returns>
		public static BNFExpression ScriptTree()
		{
			var res = new BNFExpression();
			res.Name = DEFAULT_TREE_BNF_NAME;
			res.Syntaxis = new List<Token[]>();
			res.Syntaxis.Add(new[] { new Token(TokenType.BNFConstruct, DEFAULT_HEADER_BNF_NAME), new Token(TokenType.BNFConstruct, DEFAULT_SEQUENCE_BNF_NAME) });
			res.IsRecursive = false;
			return res;
		}
		#endregion

		#region - Utility methods. -
		/// <summary>
		/// [molecule]
		/// 
		/// Substitutes specified keyword by a new variant.
		/// </summary>
		/// <param name="oldKey"></param>
		/// <param name="newKey"></param>
		public void SubstituteKeyword(string oldKey, string newKey)
		{
			foreach (var tokens in Syntaxis)
			{
				foreach (var token in tokens)
				{
					if (token.TokenType == TokenType.Keyword
						&& string.Compare(token.Text, oldKey, true) == 0)
					{
						token.Text = newKey;
					}
				}
			}
		}
		#endregion
	}
}